/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package twoTeam;

import ants.Conocimiento;
import ants.Constantes;
import ants.Perspective;
import ants.Perspective_k;
import java.awt.Point;
import java.util.ArrayList;
import java.util.PriorityQueue;
import java.util.Random;

/**
 *
 * @author uhgy3k
 */
public class Hormiga {

    int tipo;
    int id;
    float area;
    int mapa[][];
    /*
     * 0 - Desconocido 1 - Libre 2 - Bloqueado 3 - Comida
     */
    Point pos;
    Point origen;
    int estado;
    PriorityQueue<Nodo> heap;
    int[][] distancia;
    int distance;
    private ArrayList<Integer> camino;
    private int paso;
    Conocimiento[] conocimiento;
    int player;
    int objetivo;

    Hormiga(int i, int t, int a, int b, int Id) {
        tipo = t;
        id = i;
        area = (a - 2) * (b - 2) / 2;
        mapa = new int[2 * a][2 * b];
        pos = new Point();
        pos.x = b;
        pos.y = a;
        origen = (Point) pos.clone();
        estado = 0;
        distance = 0;
        conocimiento = null;
        player = Id;
    }

    public Respuesta getMovimiento(Perspective p, float[][] comida, float[][] exploracion, float[][] dist, float[][] ataque, Perspective_k p_k) {
        Respuesta r = new Respuesta();
        r.direccion = 4;

        /**
         * ***************
         */
        /*
         * Guardado de Mapa /*****************
         */
        /*
         *
         * int initialX = pos.x - 1, initialY = pos.y - 1;
         *
         * for (int i = 0; i < 3; i++) { for (int j = 0; j < 3; j++) {
         * //if(mapa[initialX + i][initialY + j] == 0) //{ if
         * (p.tiles[i][j].food == true) { mapa[initialY + i][initialX + j] = 3;
         * } else if (p.tiles[i][j].type == Constantes.libre) { mapa[initialY +
         * i][initialX + j] = 1; } else if (p.tiles[i][j].type ==
         * Constantes.obstaculo) { mapa[initialY + i][initialX + j] = 2; } //}
         *
         * }
         * }
         */
        /*
         * for (int i = 0; i < mapa.length; i++) { for (int j = 0; j <
         * mapa.length; j++) {
         *
         * if (origen.x == j && origen.y == i) { System.out.print("s"); } else {
         * System.out.print(mapa[i][j]); } } System.out.println(""); }
         */
        switch (tipo) {
            case Constantes.warrior_id:
                /*
                 * Se me ocurre como estrategia lo siguiente: cuando las
                 * exploradores localizan comida las recolectoras salen del
                 * hormiguero en busca de la comida, propongo que las guerreras
                 * salgan al mismo tiempo (escoltandolas), pero a diferencia de
                 * las recolectoras al llegar a la fuente de alimento estas se
                 * quedaran protegiendola hasta que la comida se agote, cuando
                 * la guerrera detecte que no queda mas comida regresa al
                 * hormiguero y busca una nueve fuente de alimento a la cual
                 * proteger
                 *
                 *
                 */
                if (!p.tiles[1][1].food) {
                    float limite = 0.1f;
                    if (ataque[1][1] > limite || comida[1][1] > limite) {
                        if (ataque[1][1] > comida[1][1] + 0.2) {
                            r.direccion = moverMayor(ataque);
                        } else {
                            movimientoBusquedaComida(comida, r);
                        }
                    } else {
                        this.explorar(r, p, exploracion, dist);
                    }
                }
                break;
            /*
             * if (pos.equals(origen)) { paso = 0; distance = 0; estado = 0; }
             *
             * if(p.tiles[1][1].food) { estado = 1; } else { estado = 0; }
             *
             * switch (estado) { case 0: this.explorar(r, p, exploracion, dist);
             * break; case 1: if (pos.equals(origen)) { estado = 0; } else { if
             * (p.tiles[1][1].food) { } else { r.direccion = moverMayor(dist); }
             * } break; } break;
             */

            case Constantes.explorer_id:
                // Si regresas al hormiguero vas a buscar comida
                /*
                 * for(int x = 0; x < conocimiento.length; x++)
                 * System.out.print(conocimiento[x].player+"/"+conocimiento[x].tipo+"
                 * "); System.out.println();
                 */
                if (pos.equals(origen)) {
                    paso = 0;
                    distance = 0;
                    estado = 0;
                }
                if (p.tiles[1][1].food) {
                    estado = 1;
                }
                int t = 4;
                switch (estado) {
                    case 0: // Expoloracion 
                        int max = 0;
                        for (int x = 0; x < p_k.tiles.length; x++) {
                            for (int y = 0; y < p_k.tiles[x].length; y++) {
                                for (int z = 0; z < p_k.tiles[x][y].AntType.length; z++) {
                                    if (conocimiento[z].player != player && conocimiento[z].tipo == Constantes.worker_id && p_k.tiles[x][y].AntType[z] > max) {
                                        estado = 2;
                                        max = p_k.tiles[x][y].AntType[z];
                                        t = (x * 3) + y;
                                        objetivo = conocimiento[z].player;
                                    }
                                }
                            }
                        }
                        if (max > 0) {
                            for (int a = 0; a < 3; a++) {
                                for (int b = 0; b < 3; b++) {
                                    int dis = Math.abs(a - (int) (t / 3)) + Math.abs(b - (int) (t % 3));
                                    if (p.tiles[a][b].type == Constantes.libre) {
                                        if (ataque[a][b] < 0.9f / (dis + 1)) {
                                            r.dA[a][b] = (0.9f / (dis + 1)) - ataque[a][b];
                                        }
                                    }
                                }
                            }
                            r.direccion = t;
                        } else {
                            float f = feromona(dist, p);
                            r.dD[1][1] = f;
                            this.explorar(r, p, exploracion, dist);
                        }
                        break;
                    case 1: // Dejar rasto de comida
                        if (pos.equals(origen)) {
                            estado = 0;
                            r.dC = feromonaComida(comida);
                        } else {
                            if (p.tiles[1][1].food) {
                                r.dC[1][1] = 1.0f;
                            } else {
                                r.dC = feromonaComida(comida);
                            }
                            r.direccion = moverMayor(dist);
                        }
                        break;
                    case 2: // Seguir                        
                        for (int x = 0; x < p_k.tiles.length; x++) {
                            for (int y = 0; y < p_k.tiles[x].length; y++) {
                                for (int z = 0; z < p_k.tiles[x][y].AntType.length; z++) {
                                    if (conocimiento[z].player == objetivo && conocimiento[z].tipo == Constantes.worker_id && p_k.tiles[x][y].AntType[z] > 0) {
                                        t = (x * 3) + y;
                                    }
                                }
                            }
                        }
                        for (int a = 0; a < 3; a++) {
                            for (int b = 0; b < 3; b++) {
                                int dis = Math.abs(a - (int) (t / 3)) + Math.abs(b - (int) (t % 3));
                                if (p.tiles[a][b].type == Constantes.libre) {
                                    if (ataque[a][b] < 0.9f / (dis + 1)) {
                                        r.dA[a][b] = (0.9f / (dis + 1)) - ataque[a][b];
                                    }
                                }
                            }
                        }
                        r.direccion = t;
                        break;
                }
                break;
            case Constantes.worker_id:
                // Si llegaste a comida dejas feromona 1 y cambias a regresoComida
                if (p.Sicomida == 1) {
                    estado = 1;
                }
                // Si regresas al hormiguero vas a buscar comida
                if (pos.equals(origen)) {
                    paso = 0;
                    distance = 0;
                    estado = 0;
                }
                switch (estado) {
                    case 0:
                        movimientoBusquedaComida(comida, r);
                        break;
                    case 1:
                        movimientoRegresoComida(dist, r, p);
                        if (p.tiles[1][1].food) {
                            r.dC[1][1] = 1.0f;
                        } else {
                            r.dC = feromonaComida(comida);
                        }
                        break;
                }
                break;
        }

        return r;
    }

    void movimientoRegresoComida(float dist[][], Respuesta r, Perspective p) {

        r.direccion = moverMayor(dist);

    }

    void setConocimiento(Conocimiento knowledge[]) {

        conocimiento = knowledge;

    }

    void conocimientoMerge(Conocimiento nuevoConocimiento[]) {
        Conocimiento[] temp = conocimiento;

        for (int x = 0; x < temp.length; x++) {
            Conocimiento element = temp[x];
            if (element.player == 0 && element.tipo == 0) {
                temp[x] = nuevoConocimiento[x];
            }

        }


    }

    Conocimiento[] getConocimiento() {
        return conocimiento;
    }

    void movimientoBusquedaComida(float comida[][], Respuesta r) {
        //seleccion de casilla con mayor cantidad de feromona;
        float suma = 0;
        for (int x = 0; x < 3; x++) {
            for (int y = 0; y < 3; y++) {
                if (comida[x][y] > comida[1][1] && comida[x][y] > 0.1f) {
                    suma += comida[x][y];
                }
            }
        }
        if (suma == 0) {
            estado = 1;
            r.direccion = 4;
        } // realizar movimiento
        else {// solo muevo si x lo minino es mas grande k 0.1            
            int d = 0;
            int direccion = 4;
            Random ran = new Random();
            float t = suma * ran.nextFloat();
            suma = 0;
            for (int x = 0; x < 3; x++) {
                for (int y = 0; y < 3; y++) {
                    if (comida[x][y] > comida[1][1] && comida[x][y] > 0.1f) {
                        if (t > suma && t <= suma + comida[x][y]) {
                            direccion = d;
                        }
                        suma += comida[x][y];
                    }
                    d++;
                }
            }
            r.direccion = direccion;
        }
    }

    private Respuesta explorar(Respuesta r, Perspective p, float[][] exploracion, float[][] dist) {
        float suma = 0;
        int d = this.verComida(p);
        if (d == -1) {
            for (int x = 0; x < 3; x++) {
                for (int y = 0; y < 3; y++) {
                    if ((x != 1 || y != 1) && p.tiles[x][y].type == Constantes.libre) {
                        suma += 1 - exploracion[x][y];
                    }
                }
            }
            Random ran = new Random();
            float t = suma * ran.nextFloat();
            float tmp = 0;
            d = 0;
            for (int x = 0; x < 3; x++) {
                for (int y = 0; y < 3; y++) {
                    r.dE[x][y] = 0.0f;
                    if ((x != 1 || y != 1) && p.tiles[x][y].type == Constantes.libre) {
                        tmp += 1 - exploracion[x][y];
                        if (t <= tmp) {
                            r.direccion = d;
                            for (int a = 0; a < 3; a++) {
                                for (int b = 0; b < 3; b++) {
                                    int dis = Math.abs(a - (int) (d / 3)) + Math.abs(b - (int) (d % 3));
                                    if (p.tiles[a][b].type == Constantes.libre) {
                                        if (exploracion[a][b] < 0.9f / (dis + 1)) {
                                            r.dE[a][b] = (0.9f / (dis + 1)) - exploracion[a][b];
                                        }
                                    }
                                }
                            }
                            return r;
                        }
                    }
                    d++;
                }
            }
        } else {
            r.direccion = d;
        }
        return r;
    }

    /*
     * void buscar() { Nodo t; do { do { t = heap.poll(); } while
     * (distancia[t.place.y][t.place.x] > 0); distancia[t.place.y][t.place.x] =
     * t.g; for (int y = 0; y < 3; y++) { for (int x = 0; x < 3; x++) { if
     * (mapa[t.place.y + y - 1][t.place.x + x - 1] == 1) { heap.add(new
     * Nodo(t.place.x + x - 1, t.place.y + y - 1, t.dist + 1,
     * heuristica(t.place), t.camino, y * 3 + x)); } } } } while (t.place.x !=
     * origen.x || t.place.y != origen.y); camino = t.camino; for (int x = 0; x
     * < camino.size(); x++) { System.out.print(camino.get(x) + " "); }
     * System.out.println(); paso = 0; }
     *
     */
    private int verComida(Perspective p) {
        int d = 0;
        for (int x = 0; x < 3; x++) {
            for (int y = 0; y < 3; y++) {
                if (p.tiles[x][y].food == true) {
                    estado = 1;
                    /*
                     * distancia = new int[mapa.length][mapa[0].length]; heap =
                     * new PriorityQueue(mapa.length * mapa[0].length, new
                     * Comparator() {
                     *
                     * @Override public int compare(Object o1, Object o2) { Nodo
                     * a = (Nodo) o1; Nodo b = (Nodo) o2; return a.dist -
                     * b.dist; } });
                     *
                     */
                    paso = 0;
                    return d;
                }
                d++;
            }
        }
        return -1;
    }

    private float feromona(float mat[][], Perspective p) {
        float ma = 0;
        for (int x = 0; x < 3; x++) {
            for (int y = 0; y < 3; y++) {
                if ((x != 1 || y != 1) && p.tiles[x][y].type == Constantes.libre) {
                    if (mat[x][y] > ma) {
                        ma = mat[x][y];
                    }
                }
            }
        }
        if (ma == 0) {
            return 1.0f;
        }
        float f = ((area * ma) - 1) / area;
        if (f > mat[1][1]) {
            return f - mat[1][1];
        }
        return 0;
    }

    private float[][] feromonaComida(float[][] comida) {
        float d[][] = new float[3][3];
        float ma = comida[1][1];
        for (int x = 0; x < 3; x++) {
            for (int y = 0; y < 3; y++) {
                if (comida[x][y] > ma) {
                    ma = comida[x][y];
                }
            }
        }
        for (int x = 0; x < 3; x++) {
            for (int y = 0; y < 3; y++) {
                float f = ((area * ma) - 2) / area;
                if (f > comida[x][y]) {
                    d[x][y] = f - comida[x][y];
                }
            }
        }
        float f = ((area * ma) - 1) / area;
        if (f > comida[1][1]) {
            d[1][1] = f - comida[1][1];
        }
        return d;
    }

    private int moverMayor(float[][] dist) {
        float ma = dist[1][1];
        int r = 4;
        int d = 0;
        for (int x = 0; x < 3; x++) {
            for (int y = 0; y < 3; y++) {
                if ((x != 1 || y != 1) && ma < dist[x][y]) {
                    ma = dist[x][y];
                    r = d;
                }
                d++;
            }
        }
        return r;
    }

    public void move(int dir) {
        switch (dir) {
            case 0:
                pos.x--;
                pos.y--;
                break;
            case 1:
                pos.y--;
                break;
            case 2:
                pos.y--;
                pos.x++;
                break;
            case 3:
                pos.x--;
                break;
            case 4:
                break;
            case 5:
                pos.x++;
                break;
            case 6:
                pos.y++;
                pos.x--;
                break;
            case 7:
                pos.y++;
                break;
            case 8:
                pos.x++;
                pos.y++;
                break;
        }
    }

    private boolean visto(Conocimiento conocimiento) {
        if (conocimiento.player != 0 && conocimiento.tipo != 0) {
            return true;
        }
        return false;
    }
}
